#ifndef _CE98FCDA_AF7B_44A4_9E09_4BD2B57BCD0E
#define _CE98FCDA_AF7B_44A4_9E09_4BD2B57BCD0E

#include "depends/incfile.h"
#include "CFunc.h"
#include "xCores.h"
#include "SysUtil.h"
#include "CrypUtil.h"
#include "DbgUtil.h"

namespace x2lib
{
    class TranCodec
    {
    public:
#pragma pack(push, 1)
        struct TranPack
        {
            static TranPack* Create(void* pData = nullptr, uint32_t nData = 0)
            {
                TranPack* pTranPack = (TranPack*)malloc(MIN_SIZE + nData);
                pTranPack->reset();
                pTranPack->Head.nBytes = nData;
                pTranPack->Head.nTotal = nData;
                pTranPack->Head.uCrc32 = CrypUtil::CalcCrc32(pData, nData);
                if (pData && nData>0) 
                { 
                    memcpy(&pTranPack->Body, pData, nData); 
                }
                return pTranPack;
            }
            static void Delete(TranPack*& pTranPack)
            {
                free(pTranPack);
                pTranPack = nullptr;
            }

            TranPack()
            {
                reset();
            }
            struct tagHead
            {
                uint8_t mgCode[16]; // 拆分包的起始标记
                uint32_t uDbgId; // 调试id，一组TranPack共享同一个id，由PostData/SendData累加，接收端校验
                uint32_t nMsgId; // 消息id，一组TranPack共享同一个id
                bool action : 1; // 0-req, 1-rep
                uint8_t retCode:7; // 0-normal
                uint32_t iSeek; // 当前TranPack::Body在完整包中的起始偏移
                uint32_t nBytes; // 拆分包总大小Body
                uint32_t nTotal; // 完整包的大小（用户调用PushBack时传入的nData，同时也等于所有拆分包Body的总和）
                uint32_t uCrc32; // 当前包Body的crc32
            }Head;
            uint8_t Body; // 取地址即可得到pData的地址
            void reset(const uint8_t mgCode[16] = nullptr)
            {
                memset(this, 0, sizeof(Head));
                if (mgCode != nullptr) { memcpy(Head.mgCode, mgCode, sizeof(Head.mgCode)); }
            }
        
            void setPack(uint32_t nMsgId, bool action, uint8_t retCode, uint32_t iSeek, uint32_t nTotal, uint8_t *pData, uint16_t nBytes)
            {
                this->Head.nMsgId = nMsgId;
                this->Head.action = action;
                this->Head.retCode = retCode;
                this->Head.iSeek = iSeek;
                this->Head.nBytes = nBytes;
                this->Head.nTotal = nTotal;
                this->Head.uCrc32 = CrypUtil::CalcCrc32(pData, nBytes);
                if (pData && nBytes > 0)
                {
                    memcpy(&this->Body, pData, nBytes);
                }
            }

            void incDbgId()
            {
                static uint32_t s_uDbgId_Counter = 1;
                this->Head.uDbgId = s_uDbgId_Counter++;
            }

            void* memAddr()
            {
                return this;
            }

            uint32_t memSize()
            {
                return MIN_SIZE + this->Head.nBytes;
            }

            uint8_t* bodyAddr()
            {
                return (uint8_t*)&this->Body;
            }
            uint32_t bodySize()
            {
                return this->Head.nBytes;
            }

            bool isValid()
            {
                if(this->Head.uCrc32 == 0) { return false ;}
                if (this->Head.nBytes > (this->Head.nTotal) || this->Head.iSeek + this->Head.nBytes != this->Head.nTotal) { return false; }
                return (this->Head.uCrc32 != CrypUtil::CalcCrc32(&this->Body, this->Head.nBytes));
            }

            static const uint8_t MIN_SIZE = sizeof(tagHead); // 最小长度：包头的大小（Head）
            // static const uint32_t MAX_SIZE = 1024*1024*32; // 最大长度
        };
        typedef TranPack::tagHead TranPackHead;
#pragma pack(pop)


        struct AbsPot
        {
            AbsPot() 
            {
                static uint32_t s_id_counter = 0;
                id = ++s_id_counter;
                uuid[0] = 0;
            }
            virtual ~AbsPot()
            {
                
            }
            uint32_t id; // 同步到DataChannel::TranPack::nSrcID/nDstID
            char uuid[64]; // 全球唯一，可以用来作为身份查找，权限验证等
        };

        struct AbsChannel
        {
            friend class TranCodec;

            struct Buffer
            {
                Buffer(uint16_t size)
                {
                    pData = (uint8_t*)calloc(1, size);
                    nData = size;
                    beginIndex = 0;
                    endIndex = 0;
                }
                virtual ~Buffer()
                {
                    free(pData);
                }

                uint8_t& operator[](uint16_t index) 
                {
                    return pData[index];
                }

                uint32_t totalBytes()
                {
                    return nData;
                }
                    
                uint32_t filledBytes()
                {
                    return (endIndex - beginIndex + totalBytes())%totalBytes();
                }
                    
                uint32_t spaceBytes()
                {
                    return totalBytes() - filledBytes();
                }

                uint8_t* pData;
                uint32_t nData;
                uint32_t beginIndex;
                uint32_t endIndex;
            };
                
            enum // auth的取值
            { // OnChannel典型流程，当C/S端BaseChannel的状态不同步时，以S端为准；
                UNKNOWN = 0, /*未知通道[C/S]，并在2倍心跳后由Transfer置为CLEANUP：权限：禁止Send/Recv，禁止心跳*/
                CLEANUP, /*立即清除[C/S]，被Transfer检测到后立即清除；权限：禁止Send/Recv，禁止心跳*/
                ACCEPTIN, /*客户端接入[S,Sr]，由Server::CylAccept产生；权限：非LOGING消息均阻止*/
                LOGINING, /*正在登陆[C->S,S->Sr]，由Client::Login发起，Server::Check处理；C端2倍alive内未收到VERPASS/VERFAIL则由Transfer转为VERFAIL，期间阻止所有其他消息；S端返回VERPASS/VERFAIL消息*/
                VERPASS, /*认证成功[S->C,Sr->S]，由Server::Check产生，Client::OnChannel处理；权限：全部通行*/
                EXITING, /*正在退出[C->S,S->Sr]，在Socket::Logout设置，发送端发送成功后在OnDataSended里修改为CLEANUP，接收端接收成功后，在OnDataRecved改为CLEANUP；权限：禁止所有*/
                VERFAIL, /*认证失败[S->C,Sr->S]，由Server::Check产生，Client::OnChannel处理；在Transfer立即改为CLEANUP；权限：全部禁止*/
                // 使用this->conn 表示是否在线
            };

            AbsChannel(uint16_t packSize = 1024 * 4) : 
                uPackSize(packSize), handle(0), auth(UNKNOWN), 
                beat(60 * 10), tick(0), tmin(0), tmout(0), conn(false), reco(0), 
                local(nullptr)//, other(nullptr) 
            {
                pPackTxed = (TranPack*)malloc(uPackSize);
                pPackRxed = (TranPack*)malloc(uPackSize);
                pPackTxBuffer = new Buffer(uPackSize * 8);
                pPackRxBuffer = new Buffer(uPackSize * 8);
            }
            virtual ~AbsChannel()
            {
                free(pPackTxed);
                free(pPackRxed);
                free(pPackTxBuffer);
                free(pPackRxBuffer);
            }

            intz_t handle;
            uint8_t auth; // 验证状态
            uint32_t beat; // 心跳间隔，单位秒
            uint32_t tick; // 最近一次收发数据的tick
            uint32_t tmin; // 建立时间戳
            uint32_t tmout; // 断开时间戳
            bool conn; // 是否连接
            uint8_t reco; // 断线重连次数，重连时间间隔使用心跳时间间隔beat；
            // 预留3个用户指针
            //void* local; // 本端描述体指针
            //void* other; // 远端描述体指针
            // template<class T> T local(){ return static_cast<T>(this->_local); }
            // template<class T> T other(){ return static_cast<T>(this->_other); }
            AbsPot* local;
            AbsPot other;

            TranPack* pPackTxed; // Listener::OnPackSended
            TranPack* pPackRxed; // Listener::OnPackRecved, by user set

        private:
            uint16_t uPackSize;

            Buffer *pPackTxBuffer; // ring queue
            Buffer *pPackRxBuffer; // ring queue
        };

        class Listener
        {
        public:
            virtual void OnConnChanged(AbsChannel* pAbsChannel)
            {
                LOG_PRINT_I("OnConnChanged: %d\n", pAbsChannel->conn);
            }
            virtual void OnBytesEnSend(uint8_t* pData, uint32_t nData)
            {
                CrypUtil::Encrypt(pData, pData, nData, WEAK_KEY);
            }
            virtual void OnBytesDeRecv(uint8_t* pData, uint32_t nData)
            {
                CrypUtil::Decrypt(pData, pData, nData, WEAK_KEY);
            }
            virtual void OnPackSended(AbsChannel* pAbsChannel)
            {
                TranPack* pPackTxed = pAbsChannel->pPackTxed;
                LOG_PRINT_I("fd=%p,uDbgId=%d,nMsgId=%d,nRecvd/nTotal=%d/%d\n", pAbsChannel->handle, pPackTxed->Head.uDbgId, pPackTxed->Head.nMsgId, pPackTxed->Head.iSeek + pPackTxed->Head.nBytes, pPackTxed->Head.nTotal);
            }
            virtual uint8_t OnPackRecved(AbsChannel* pAbsChannel, void** ppRepData, uint32_t* pnRepData)
            {
                TranPack* pPackRxed = pAbsChannel->pPackRxed;
                LOG_PRINT_I("fd=%p,uDbgId=%d,nMsgId=%d,nRecvd/nTotal=%d/%d\n", pAbsChannel->handle, pPackRxed->Head.uDbgId, pPackRxed->Head.nMsgId, pPackRxed->Head.iSeek + pPackRxed->Head.nBytes, pPackRxed->Head.nTotal);
                return 0;
            }
            virtual void OnProcessing(AbsChannel* pChannel, uint32_t dealt, uint32_t total) {};
        };

    public:
        TranCodec(bool isClient, Listener* pListener, uint8_t mgCode[16], int nPackSize = 1024 * 32, bool syncExec = false);
        virtual ~TranCodec();
        bool Init(void* userPtr);
        // uRetry重试次数（间隔15s），仅当作为Client时有效
        bool Execute(int reConnWaitsec = 15, int reConnTimes = 10);
        void UnInit(void* userPtr);
        AbsChannel* GetMyChannel();
        AbsChannel* FindChannel(std::function<bool(const AbsChannel*)> condition);

    protected:
        virtual AbsChannel* connectServer(void* userPtr) = 0;
        virtual AbsChannel* prepareServer(void* userPtr) = 0;
        virtual void releaseServer(void* userPtr) = 0;
        virtual AbsChannel* acceptClients() = 0;
        virtual void closeChannel(AbsChannel* pChannel) = 0;
        virtual void keepAlive(AbsChannel* pChannel) {};


    public:
        uint32_t PostData(AbsChannel* pChannel, uint32_t nMsgId, bool action, uint8_t retCode, const void* pData = nullptr, uint32_t nData = 0, bool isWait = true);
        uint32_t SendData(AbsChannel* pChannel, uint32_t nMsgId, bool action, uint8_t retCode, const void* pData = nullptr, uint32_t nData = 0, void* pDataout = nullptr, uint32_t nDataout = 0, bool isWait = true);

        bool pushData(uint8_t* pData, uint32_t nData, AbsChannel* pChannel, bool isTx, bool isWait);
        TranPack* pullData(AbsChannel* pChannel, bool isTx, bool isWait);

    protected:
        virtual bool ApiSend(AbsChannel* pChannel, void* pData, uint32_t nData, uint32_t* pnBytes) = 0;
        virtual bool ApiRecv(AbsChannel* pChannel, void* pData, uint32_t nData, uint32_t* pnBytes) = 0;


        bool m_isClient;
        Listener* m_pListener;
        bool m_syncExec; // Execute以同步或异步方式执行
        AbsChannel* m_pMyChannel;
        std::thread* m_pSendThread;
        std::thread* m_pRecvThread;
        std::thread* m_pAcceptThread;

    private:

        // return: 0-断开连接，1-指定的数据收发完成，2-指定的数据未收发完成
        int trySend(AbsChannel* pChannel, bool isWait);
        int tryRecv(AbsChannel* pChannel, bool isWait);

        bool m_isRunning;
        static const unsigned char WEAK_KEY = 0x12;
        std::vector<AbsChannel*> m_vecpChannel;
        xCores::Mutex m_mtxChannel;
        uint8_t m_mgCode[16];
        xCores::Signal m_signDeal;
        xCores::Signal m_signSend;
        std::set<uint32_t> m_setSyncId;
    };
}

#endif
